package main

import (
	"fmt"
	"math"
	"reflect"
	"strconv"
)

type TagType struct {
	field1 bool		"An important answer"
	field2 string	"The name of the thing"
	field3 int		"How much there are"
}

func refTag(tt TagType, x int) {
	ttType := reflect.TypeOf(tt)
	ixField := ttType.Field(x)
	fmt.Printf("%v\n", ixField.Tag)
}

type innerS struct {
	in1 int
	in2 int
}

type outerS struct {
	b int
	c float32
	int		// anonymous field
	innerS	// anonymous field
}

type A struct {
	ax, ay int
}

type B struct {
	A
	bx, by float32
}

type TwoInts struct {
	a int
	b int
}

func (tn *TwoInts) AddThem() int {
	return tn.a + tn.b
}

func (tn *TwoInts) AddToParam(param int) int {
	return tn.a + tn.b + param
}

func (tn *TwoInts) String() string {
	return "(" + strconv.Itoa(tn.a) + "/" + strconv.Itoa(tn.b) + ")"
}


type BB struct {
	thing int
}

func (b *BB) change() {
	b.thing = 1
}

func (b BB) write() string {
	return fmt.Sprint(b)
}

type Engine interface {
	Start()
	Stop()
}

type Car struct {
	Engine
}

func (c *Car) GoToWorkIn() {
	c.Start()
	c.Stop()
}

type Point struct {
	x, y float64
}

func (p *Point) Abs() float64 {
	return math.Sqrt(p.x * p.x + p.y * p.y)
}

type NamedPoint struct {
	Point
	name string
}

type Log struct {
	msg string
}

type Customer struct {
	Name string
	log *Log
}

func (l *Log) Add(s string) {
	l.msg += "\n" + s
}

func (l *Log) String() string {
	return l.msg
}

func (c *Customer) Log() *Log {
	return c.log
}

type Camera struct {

}

func (c *Camera) TakeAPicture() string {
	return "Click"
}

type Phone struct {}

func (p *Phone) Call() string {
	return "Ring Ring"
}

type CameraPhone struct {
	Camera
	Phone
}

func test6() {
	cp := new(CameraPhone)
	fmt.Println("Our new CameraPhone exhibits multiple behaviors...")
	fmt.Println("It exhibits behavior of a Camera: ", cp.TakeAPicture())
	fmt.Println("It works like a Phone too: ", cp.Call())
}

func test5() {
	c := new(Customer)
	c.Name = "Barak Obama"
	c.log = new(Log)
	c.log.msg = "1 - Yes we can!"

	c = & Customer{"Barak Obama", &Log{"1 - Yes we can!"}}
	c.Log().Add("2 - After me the world will be a better place!")
	fmt.Println(c.Log())
}

func test4() {
	n := &NamedPoint{Point{3, 4}, "Pythagoras"}
	fmt.Println(n.Abs())
}

func test3() {
	var b1 BB
	b1.change()
	fmt.Println(b1.write())

	b2 := new(BB)
	b2.change()
	fmt.Println(b2.write())
}

func test2() {
	two1 := new(TwoInts)
	two1.a = 12
	two1.b = 10

	fmt.Printf("The sum is: %d\n", two1.AddThem())
	fmt.Printf("Add them to the param: %d\n", two1.AddToParam(20))
	fmt.Printf("two1 is:%v\n", two1)
	fmt.Println("two1 is: ", two1)

	two2 := TwoInts{3, 4}
	fmt.Printf("The sum is :%d\n", two2.AddThem())
}

func test1() {
	b:=B{A{1, 2}, 3.0, 4.0}
	fmt.Println(b.ax, b.ay, b.bx, b.by)
	fmt.Println(b.A)
}


func test() {
	outer := new(outerS)
	outer.b = 6
	outer.c = 7.5
	outer.int = 60
	outer.in1 = 5
	outer.in2 = 10

	fmt.Printf("outer.b is: %d\n", outer.b)
	fmt.Printf("outer.c is: %f\n", outer.c)
	fmt.Printf("outer.int is: %d\n", outer.int)
	fmt.Printf("outer.in1 is: %d\n", outer.in1)
	fmt.Printf("outer.in2 is: %d\n", outer.in2)

	outer2 := outerS{6, 7.5, 60, innerS{5, 10}}
	fmt.Println("outer2 is:", outer2)
}



/*
* 值 t: t := &T{7, -2.35, "abc\tdef"}给 T 定义 String()，使
得 fmt.Printf("%v\n", t) 输出：7 / -2.350000 / "abc\tdef"
 */
type T struct {
	a int
	b float32
	c string
}

func (t *T) String() string {
	//return strconv.Itoa(t.a) + " / " + strconv.FormatFloat(float64(t.b), 'f', 6, 64) + " / " + t.c
	return fmt.Sprintf("%d / %f /%q", t.a, t.b, t.c)
}

func exp1012() {
	t := &T{7, -2.35, "abc\tdef"}
	fmt.Println("t is: ", t)
}

type Celsius float64

func (c Celsius) String() string {
	//return fmt.Sprintf("%d°C", c)
	return "The temperature is: " + strconv.FormatFloat(float64(c), 'f', 1, 64) + "°C"
}

func exce1013() {
	var c Celsius = 18.36
	fmt.Println(c)
}

func main() {
	tt:=TagType{true, "Barak Obama", 1}
	for i := 0; i < 3; i++ {
		refTag(tt, i)
	}

	test()
	test1()
	test2()
	test3()
	test4()
	test5()
	test6()
	exp1012()
	exce1013()
}
